package com.nxy.cpfsfe.busi.bolag;


import com.adtec.starring.datapool.CompSDO;
import com.adtec.starring.datapool.EPOper;
import com.adtec.starring.exception.BaseException;
import com.adtec.starring.struct.dta.DtaInfo;
import com.adtec.starring.util.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.nxy.cpfsfe.config.CpfsFeAllConfig;
import com.nxy.cpfsfe.enumtype.*;
import com.nxy.cpfsfe.mybatis.mapper.TbAMapper;
import com.nxy.cpfsfe.mybatis.mapper.ToSysNtcMapper;
import com.nxy.cpfsfe.mybatis.mapper.TsPCmdMapper;
import com.nxy.cpfsfe.mybatis.pojo.TbA;
import com.nxy.cpfsfe.mybatis.pojo.TsPCmd;
import com.nxy.cpfsfe.service.CpfsService;
import com.nxy.cpfsfe.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 * Description:通用报文丢失处理Bean(11报文)
 *
 * @author
 * @data 2019年9月7日
 */

public class NCSMsgLossProcSrvBean  implements CpfsService {
	
	
	private final static Logger LOGGER = LoggerFactory.getLogger(NCSMsgLossProcSrvBean.class);
	SqlSession sqlSession = null;	

	/**
	 * 异步处理
	 * Description:通用处理服务
	 *
	 * @author
	 * @data 2019年8月24日
	 */
	
	public void  doService() {
		// TODO 自动生成的构造函数存根
		
		String tpId = DtaInfo.getInstance().getTpId();
		sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");		
		// 获取输入
		CompSDO inputSdo = (CompSDO) EPOper.getCompSDO(tpId, "ReqBody"); // 获取输入接口				
		// 业务报文			
		String bizMsg = (String) inputSdo.getValue("BizMsg")!=null?(String) inputSdo.getValue("BizMsg"):"";
		LOGGER.info("接收到NCS报文丢失处理输入BizMsg报文数据：[{}]" , bizMsg);
					
		String msgCd =XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/msgCd");	
		String refMsgCd =XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refMsgCd");
        String prcCd = XmlUtil.getValByXPath(bizMsg,"/transaction/body/DscrdMsgNtfctn/DscrdInf/PrcCd");
        String rjctInf = XmlUtil.getValByXPath(bizMsg,"/transaction/body/DscrdMsgNtfctn/DscrdInf/RjctInf");
		if(!MsgCdOrTpEnum.MSGCD_911.getCode().equals(msgCd)){
			LOGGER.warn("NCS报文丢失处理报文标识号应为:[{}]，此报文标识号：[{}]非法",MsgCdOrTpEnum.MSGCD_911.getCode(),msgCd);
			return;
		}
		if(StringUtils.isEmpty(refMsgCd)){
			LOGGER.warn("NCS报文丢失处理报文原报文标识号为空");
			return;
		}
		LOGGER.info("开始处理{}交易的NCS报文丢失处理",refMsgCd);
		if(MsgCdOrTpEnum.MSGCD_120.getCode().equals(refMsgCd)||MsgCdOrTpEnum.MSGCD_140.getCode().equals(refMsgCd)||MsgCdOrTpEnum.MSGCD_142.getCode().equals(refMsgCd)){			
			Map<String, Object> map = xml2BizMap(bizMsg);
			map.put("refMsgCd",refMsgCd);
			map.put("bizSta",StatEnum.BIZSTA_FAIL.getCode());
			updateStat(sqlSession,map,bizMsg);

			//向Nginx发送通知
			respNginx(sqlSession,map);
		}else if(MsgCdOrTpEnum.MSGCD_805.getCode().equals(refMsgCd)){
			CpfsFeAllConfig.jedisCluster.publish(XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSndMbrCd")+XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb"),bizMsg);
			LOGGER.info("redis消息发布者={}",XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSndMbrCd")+XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb"));
			//成员行登录退出应答处理
			LOGGER.debug("NCS登录应答报文标识号应为:[{}]，此报文标识号为：[{}]",MsgCdOrTpEnum.MSGCD_911.getCode(),msgCd);
			LOGGER.info("NCS返回响应码为:[{}],错误信息为:[{}]",prcCd,rjctInf);
		}else if(MsgCdOrTpEnum.MSGCD_303.getCode().equals(refMsgCd)){
			CpfsFeAllConfig.jedisCluster.publish(XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSndMbrCd")+XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb"),bizMsg);
			LOGGER.info("redis消息发布者={}",XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSndMbrCd")+XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb"));
			SqlSession sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");
			try {
				Map<String, String> bizmap = new HashMap<String, String>();				
				bizmap.put("bizSta", StatEnum.BIZSTA_FAIL.getCode());					
				bizmap.put("sndOrgNo", XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSndMbrCd"));
				bizmap.put("seqNb", XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb"));
				ToSysNtcMapper toSysNtc = sqlSession.getMapper(ToSysNtcMapper.class);
				toSysNtc.update(bizmap);
			} catch (Throwable e) {
				LOGGER.error("303自由格式ToSysNtc表更新异常,SeqNb=[" + XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb")+"]",e);
			}
		}else if(MsgCdOrTpEnum.MSGCD_365.getCode().equals(refMsgCd)){
			//资金调拨应答处理
			LOGGER.debug("资金调拨应答报文标识号应为:[{}]，此报文标识号为：[{}]",MsgCdOrTpEnum.MSGCD_911.getCode(),msgCd);
			LOGGER.info("NCS返回响应码为:[{}],错误信息为:[{}]",prcCd,rjctInf);
			String refSeqNb =XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb");
			String sndAppCd = XmlUtil.getSysIdBySeqNb(refSeqNb);
			if(SysEcodeEnum.EPAY.getCode().equals(sndAppCd) || SysEcodeEnum.EMAN.getCode().equals(sndAppCd)){
				returnGWMsgLossProc(bizMsg,sndAppCd);
			}
		}else{
			//其他报文需根据refSeqNb字段获取原交易的发起的业务系统
			String refSeqNb =XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/refSeqNb");
			String sndAppCd = XmlUtil.getSysIdBySeqNb(refSeqNb);
			if(SysEcodeEnum.EPAY.getCode().equals(sndAppCd) || SysEcodeEnum.EMAN.getCode().equals(sndAppCd)){
				returnGWMsgLossProc(bizMsg,sndAppCd);
			}
		}
	
	}
	
		
	
	
	//更新原交易状态
	private void updateStat(SqlSession sqlSession,Map map,String bizMsg) {
		try{				
			TbA tbA = queryOrgAgSeq(sqlSession, map);
			if(tbA!=null){
				map.put("cpfsSeqNo",tbA.getCpfsSeqNo());//前置流水号
			}
			TsPCmd tsPCmd = queryOrgBizSeq(sqlSession, map);
			if(tbA!=null && tsPCmd!=null){
				//更新账务流水交易状态
				map.put("updTm", DateUtil.getTimestamp(new Date()));
				map.put("orgnBizSta",tbA.getBizSta());
				//更新支付流水交易状态
				int tsPCmdUpdateNum = sqlSession.getMapper(TsPCmdMapper.class).updateByMap(map);
				//更新账务流水交易状态
				int tbAUpdateNum = sqlSession.getMapper(TbAMapper.class).updateByMap(map);
				LOGGER.info("账务流水表TbA更新数据成功：[{}]条，cpfsSeqNo=[{}];支付流水表tsPCmd更新数据成功：[{}]条,cpfsSeqNo=[{}]",tbAUpdateNum,tbA.getCpfsSeqNo(),tsPCmdUpdateNum,tsPCmd.getCpfsSeqNo());

				if(tbAUpdateNum==0 && tsPCmdUpdateNum==0){
					LOGGER.error("更新数据异常：业务流水表TbA和支付流水表tsPCmd,更新数据条数不符合预期：comMsgId：["+map.get("comMsgId")+"]");
					return;
				}
				if(SysEcodeEnum.EPAY.getCode().equals(tbA.getSndSysId()) || SysEcodeEnum.EMAN.getCode().equals(tbA.getSndSysId())){
					returnGWMsgLossProc(bizMsg,tbA.getSndSysId());
				}				
			}else{
				LOGGER.error("原交易不存在处理方式待确认,comMsgId:"+(String)map.get("comMsgId"));
			}
		
		}catch (Throwable e) {
			LOGGER.error("更新数据失败：业务流水表TbA和支付流水表tsPCmd：comMsgId：["+map.get("comMsgId")+"]",e);
		}
	}
	

	//查询账务信息
	private TbA queryOrgAgSeq(SqlSession sqlSession,Map map) {
		TbAMapper tbAMapper = sqlSession.getMapper(TbAMapper.class);
		TbA tbA = new TbA();
		tbA.setComMsgId((String)map.get("comMsgId"));
		tbA.setAcqOrgId((String)map.get("acqOrgId"));
		TbA tbAResult = tbAMapper.query(tbA);	
				
		return tbAResult;

	}
	
	//查询支付信息
	private TsPCmd queryOrgBizSeq(SqlSession sqlSession,Map map) {	
		TsPCmdMapper tsPCmdMapper = sqlSession.getMapper(TsPCmdMapper.class);
		TsPCmd tsPCmd = new TsPCmd();	
		//tsPCmd.setComMsgId((String)map.get("comMsgId"));
		tsPCmd.setCpfsSeqNo((String)map.get("cpfsSeqNo"));
		tsPCmd.setAcqOrgId((String)map.get("acqOrgId"));
		TsPCmd tsPCmdResult = tsPCmdMapper.query(tsPCmd);
				
		return tsPCmdResult;

	}
	
	
	public void returnGWMsgLossProc(String bizMsg,String sndAppCd) {

	     String tpId = DtaInfo.getInstance().getTpId();
	     String msgCd =XmlUtil.getValByXPath(bizMsg,"/transaction/header/msg/msgCd");
		 
		 EPOper.put(tpId, "ReqBean[0].head[0].rcvAppCd", sndAppCd);
    	 EPOper.put(tpId, "ReqBean[0].head[0].reqServCd", msgCd);
	     EPOper.getCompSDO(tpId, "ReqBody").setValue("BizMsg",bizMsg);
	     RpcCommUtil.getInstance().rpcFeToGW(tpId, RpcOutputInfoEnum.OutputName_Pub_Cpfsgw.getCode(),RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());
			
	}

	/**
	 *	根据原支付流水的报文编号，向Nginx返回响应
	 */
	private void respNginx(SqlSession sqlSession,Map<String, Object> map){

		TsPCmd origTsPCmdQR = null;
		TbA origTbAQR = null;
		try{
			TsPCmdMapper tsPCmdMapper = sqlSession.getMapper(TsPCmdMapper.class);
			TbAMapper tbAMapper = sqlSession.getMapper(TbAMapper.class);

			TbA origTbAQC = new TbA();
			origTbAQC.setComMsgId((String)map.get("comMsgId"));
			origTbAQC.setAcqOrgId((String)map.get("acqOrgId"));
			origTbAQR = tbAMapper.query(origTbAQC);

			TsPCmd origTsPCmdQC = new TsPCmd();
			origTsPCmdQC.setCpfsSeqNo(origTbAQR.getCpfsSeqNo());
			origTsPCmdQC.setAcqOrgId(origTbAQR.getAcqOrgId());
			origTsPCmdQR = tsPCmdMapper.query(origTsPCmdQC);

			if(MsgCdOrTpEnum.MSGTD_103.getCode().equals(origTsPCmdQR.getMsgTp())){
				sndNginxResp(origTsPCmdQR,origTbAQR);
			}
		}catch (BaseException e){
			throw e;
		}catch (Exception e){
			String errMsg = String.format("向业务系统[%s]返回[%s]的响应[CPFS.501或CPFS.502]失败，chlSeqNo=[%s]，[%s]",origTsPCmdQR.getBizSysId(),origTsPCmdQR.getMsgTp(),origTbAQR.getChlSeqNo(),e.getMessage());
			throw new BaseException(RespCd.NCPO0005,e,errMsg);
		}

	}

	/**
	 *	发送Nginx响应
	 */
	private void sndNginxResp(TsPCmd tsPCmd,TbA tbA) throws Exception{

		String resp501Msg = buildNginxResp(tsPCmd, tbA, MsgCdOrTpEnum.MSGTD_501.getCode());
		String resp502Msg = buildNginxResp(tsPCmd, tbA, MsgCdOrTpEnum.MSGTD_502.getCode());

		JSONObject addInfo = JSONObject.parseObject(tsPCmd.getAddInfo());

		Map<String,String> params = new HashMap<String,String>();
		params.put("/root/MsgHeader/MsgTp",tsPCmd.getMsgTp());
		params.put("/root/MsgHeader/CorrId",tsPCmd.getComMsgId());
		params.put("/root/MsgHeader/SndSysId",tsPCmd.getBizSysId());
		params.put("/root/MsgHeader/SndBankId",tsPCmd.getSndBNo());
		params.put("NginxUrl",addInfo.getString("NginxUrl"));
		params.put("/root/MsgHeader/ClbckUrl",addInfo.getString("ClbckUrl"));

		HttpUtil.responseSendJson(resp501Msg,resp502Msg,params);

		LOGGER.info("向业务系统[{}]返回[{}]的响应[CPFS.501或CPFS.502]成功，chlSeqNo=[{}]",tsPCmd.getBizSysId(),tsPCmd.getMsgTp(),tbA.getChlSeqNo());

	}

	/**
	 * 	构建响应Nginx的报文
	 */
	private String buildNginxResp(TsPCmd tsPCmd,TbA tbA,String msgTp) throws Exception{

		Map<String,String> buildMap = new HashMap<String,String>();
		buildMap.put("RcvSysId", tsPCmd.getBizSysId());
		buildMap.put("SndBankId",tsPCmd.getRcvBNo());
		buildMap.put("RcvBankId",tsPCmd.getSndBNo());
		buildMap.put("CorrId",tsPCmd.getComMsgId());
		buildMap.put("TrxId",tsPCmd.getXSeqNo());
		buildMap.put("OriTrxId",tsPCmd.getXSeqNo());
		buildMap.put("TrxStsCd",RespCd.NCPI0000);
		buildMap.put("BizStsCd",tsPCmd.getBizSta());
		buildMap.put("BizStsDesc",tbA.getErrDesc());
		buildMap.put("MsgId",tbA.getChlSeqNo());
		buildMap.put("EndToEndId",tsPCmd.getEndToEndId());
		buildMap.put("SttlmDt",DateUtil.date4Str(tsPCmd.getCpfsD()));
		buildMap.put("TrxPurpose",tsPCmd.getpInfo());
		buildMap.put("TrxRemark",tbA.getReserved1());

		if(MsgCdOrTpEnum.MSGTD_501.getCode().equals(msgTp)){
			buildMap.put("InstalAmt","0.00");

			return ResponseUtil.buildGeneral501Xml(buildMap);
		}else{
			buildMap.put("TrxCtgy",tsPCmd.getBizTyp());
			buildMap.put("TxNcsId",tbA.getChlSeqNo());
			buildMap.put("TrxAmt",tsPCmd.getOrdAmt().toPlainString());
			buildMap.put("TrxSysId",tbA.getpCId());
			buildMap.put("TrxChnlTp","07");

			return ResponseUtil.buildGeneral502Xml(buildMap);
		}

	}
		     		     
	public Map xml2BizMap (String bizMsg){
	    //拆解xml报文为map
		Map<String, Object> map = null;
		try{
			Map xml2BizMap = XmlUtil.xml2Map(bizMsg);	
			//把map<String, String>转换成map<String, Object>
			map = xml2BizMap;		
			map.put("comMsgId",(String)map.get("/transaction/body/DscrdMsgNtfctn/DscrdInf/MsgId"));//原seqNb
			map.put("bizSysD",(String)map.get("/transaction/body/DscrdMsgNtfctn/DscrdInf/OrigSndDt"));//原交易时间
			map.put("acqOrgId",(String)map.get("/transaction/header/msg/refSndMbrCd"));//acqOrgId
	
			map.put("sndOrgId",(String)map.get("/transaction/header/msg/refSndMbrCd"));//原发起行行号TbA
			map.put("sndBNo",(String)map.get("/transaction/header/msg/refSndMbrCd"));//原发起行行号TbA
			
			map.put("chlXCd",(String)map.get("/transaction/body/DscrdMsgNtfctn/DscrdInf/MT"));//原报文编号
			map.put("errCd",(String)map.get("/transaction/body/DscrdMsgNtfctn/DscrdInf/PrcCd"));	
			map.put("respSta",StatEnum.STAR_PR01.getCode());//业务状态
			map.put("respMsgTyp",(String)map.get("/transaction/header/msg/msgCd"));
			map.put("errDesc",(String)map.get("/transaction/body/DscrdMsgNtfctn/DscrdInf/RjctInf"));
			LOGGER.info("NCSMsgLossProcSrvBean更新表参数map：[{}]" , map.toString());
			}catch (Throwable e){
				throw new BaseException(RespCd.NCPO0101,e,MsgCdOrTpEnum.MSGCD_911.getCode()+"报文解包异常");
			}
		return map;
		
	}


}

























